/**
 *@description:
 *@file: texture2d.cpp
 *@author: snow-tyan
 *@email: zziywang@163.com
 *@date: 30 January 2023
 *@copyright: 2018-2022 AiRiA. All rights reserved.
 */

#include "mygl/texture2d.h"
#include "mygl/util.h"
#include "mygl/es_image.h"

namespace mygl {

Texture2D::Texture2D(bool flip)
    : id_(0),
      es_image_(std::make_shared<EsImage>(flip)),
      width_(0),
      height_(0),
      internal_format_(GL_RGB),
      image_format_(GL_RGB) {}

Texture2D::Texture2D(GLuint width, GLuint height)
    : id_(0),
      es_image_(std::make_shared<EsImage>()),
      width_(width),
      height_(height),
      internal_format_(GL_RGB),
      image_format_(GL_RGB) {}

Texture2D::~Texture2D() {}

int Texture2D::Generate(const std::string& image_path) {
  CHECK_RET(es_image_->LoadImage(image_path) == 0, -1);
#ifdef _DEBUG
  es_image_->PrintLoadTime();
  es_image_->PrintImageInfo();
#endif
  // update parameter
  width_ = es_image_->width;
  height_ = es_image_->height;
  switch (es_image_->channels) {
    default:
    case 3:
      internal_format_ = image_format_ = GL_RGB;
      break;
    case 1:
      internal_format_ = image_format_ = GL_RED;
      break;
    case 4:
      internal_format_ = image_format_ = GL_RGBA;
      break;
  }
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  this->generate();
  glBindTexture(GL_TEXTURE_2D, id_);
  glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, es_image_->width, es_image_->height, 0,
               image_format_, GL_UNSIGNED_BYTE, es_image_->data);
  glBindTexture(GL_TEXTURE_2D, GL_NONE);
  return 0;
}

int Texture2D::GenerateVideo(const std::string& rgb_file) {
  auto begin = TimeNow();
  CHECK_MSG(0 == ReadRgb888Video(rgb_file, width_, height_, datas_),
            "Read RGB888 file failed");
  auto end = TimeNow();
#ifdef _DEBUG
  printf("load file cost %.2fms\n", CalcPerf(begin, end));
  printf("frames: %zu, rgb_size: %zu\n", datas_.size(), datas_[0].size());
#endif
  this->generate();
  return 0;
}

void Texture2D::GenerateWithoutData(int width, int height) {
  width_ = width;
  height_ = height;
  image_format_ = internal_format_ = GL_RGB;
  this->generate();
}

void Texture2D::generate() {
  // Create Texture
  glGenTextures(1, &id_);
  glBindTexture(GL_TEXTURE_2D, id_);
  // glGenerateMipmap(GL_TEXTURE_2D);
  //  Set Texture wrap and filter modes
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, width_, height_, 0, image_format_,
               GL_UNSIGNED_BYTE, nullptr);
  // Unbind texture
  glBindTexture(GL_TEXTURE_2D, GL_NONE);
}

void Texture2D::LoadImage(GLuint frame) {
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, id_);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_, height_, 0, GL_RGB, GL_UNSIGNED_BYTE,
               datas_[frame].data());
}

void Texture2D::Bind() const { glBindTexture(GL_TEXTURE_2D, id_); }

void Texture2D::BindData(uint8_t* data) const {
  glBindTexture(GL_TEXTURE_2D, id_);
  glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, width_, height_, 0, image_format_,
               GL_UNSIGNED_BYTE, data);
  // glBindTexture(GL_TEXTURE_2D, GL_NONE);
}

void Texture2D::BindData(uint8_t* data, int width, int height) const {
  glBindTexture(GL_TEXTURE_2D, id_);
  glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, width, height, 0, image_format_,
               GL_UNSIGNED_BYTE, data);
  // glBindTexture(GL_TEXTURE_2D, GL_NONE);
}

void Texture2D::DeleteTextures() const { glDeleteTextures(1, &id_); }

}  // namespace mygl
